﻿using System;
using System.Net.Mail;
using System.Web;
using System.Web.Mvc;
using mvcForum.Core;
using mvcForum.Core.Specifications;
using mvcForum.Web.ViewModels;
using SimpleAuthentication.Mvc;
using mvcForum.Core.Interfaces.Services;
using mvcForum.Core.Interfaces.Data;

namespace mvcForum.Web.Areas.Forum.Controllers {

	public class AuthController : IAuthenticationCallbackProvider {
		private readonly IMembershipService memberService;
		private readonly IFormsAuthenticationService forms;
		private readonly IContext context;

		public AuthController(IMembershipService memberService,
								IContext context,
								IFormsAuthenticationService forms) {
			this.memberService = memberService;
			this.context = context;
			this.forms = forms;
		}

		public ActionResult OnRedirectToAuthenticationProviderError(HttpContextBase context, String errorMessage) {
			return new ViewResult {
				ViewName = "AuthenticateCallback",
				ViewData = new ViewDataDictionary(new {
					ErrorMessage = errorMessage
				})
			};
		}

		public ActionResult Process(HttpContextBase context, AuthenticateCallbackData model) {
			String username = String.Format("[{0}][{1}]", model.AuthenticatedClient.ProviderName, model.AuthenticatedClient.UserInformation.Id);
			IAccount account = this.memberService.GetAccount(username);
			if (account == null) {
				// New external user, let's create the user etc.
				MailAddress email = new MailAddress(String.Format("{0:ddMMyyyy-hhmmss}repl@ce.this", DateTime.UtcNow));
				try {
					email = new MailAddress(model.AuthenticatedClient.UserInformation.Email);
				}
				catch { }

				String errorMessage;
				// Random password, and username from provider.
				if (this.memberService.CreateAccount(username, new Guid().ToString(), email.Address, out errorMessage)) {
					account = this.memberService.GetAccount(username);
					if (account != null) {
						IRepository<ForumUser> fuRepo = this.context.GetRepository<ForumUser>();
						ForumUser fu = fuRepo.ReadOne(new ForumUserSpecifications.SpecificProviderUserKey(account.ProviderUserKey.ToString()));
						if (fu != null) {
							fu.Name = model.AuthenticatedClient.UserInformation.UserName;
							fu.EmailAddress = account.EmailAddress.EndsWith("repl@ce.this") ? account.EmailAddress : account.EmailAddress + "repl@ce.this";
							fu.FullName = model.AuthenticatedClient.UserInformation.Name;
							fu.Active = true;
							fu.ExternalAccount = true;
							fu.ExternalProvider = model.AuthenticatedClient.ProviderName;
							fu.ExternalProviderId = model.AuthenticatedClient.UserInformation.Id;
							fuRepo.Update(fu);
							this.context.SaveChanges();
						}
					}
					else {
						// TODO:
						return new HttpStatusCodeResult(500);
					}
				}
				else {
					// TODO:
					return new HttpStatusCodeResult(500);
				}
			}
			else {
				// TODO: Validate same provider etc...!!
				IRepository<ForumUser> fuRepo = this.context.GetRepository<ForumUser>();
				ForumUser fu = fuRepo.ReadOne(new ForumUserSpecifications.SpecificProviderUserKey(account.ProviderUserKey.ToString()));
				if (fu != null) {
					// Not an external account? Or external, but with a different provider?
					if (!fu.ExternalAccount || (fu.ExternalAccount && fu.ExternalProvider != model.AuthenticatedClient.ProviderName)) {
						// TODO: ????
						return new RedirectResult("/forum/account/external");
					}
				}
				else {
					// TODO:
					return new HttpStatusCodeResult(500);
				}
			}

			this.forms.SignIn(username, false);

			return new RedirectResult("/forum");
		}
	}
}